#include "interpreteur.h"

FILE *fpcode;			// Le fichier p_code
struct pile *pExecution;	// La pile d'exécution
struct liste *tableSymbole;	// La table des symbôles
struct pcode *p_code;		// Les instructions pcode
struct pa *pArret;		// Les points d'arrêts
struct pile *pLigne;		// Empile les numéros de ligne (appel de fonction)

int counter=-1;
int start=0;

int execute_pa()
{	
	if(counter==-1) return ER_COUNTER;
	if(p_code->size==0) return ER_PCODE;

	int arret=lireSuivant(pArret), res;

	while(counter<arret)
	{	
		if(start==1)
		{
			if(strcmp(p_code->codes[counter]->codeOp, "LOD")==0)
			{
				exec_LOD(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "LIT")==0) 
			{
				exec_LIT(counter);	
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "OPR")==0)
			{
				res=exec_OPR(counter);
				if(res!=0) return res;
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "JMP")==0)
				counter=exec_JMP(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "JPC")==0)
				counter=exec_JPC(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "SFL")==0)
			{
				exec_SFL(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "STO")==0)
			{
				res=exec_STO(counter); 
				if(res!=0) return res; 
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "OUT")==0)
			{ 
				exec_OUT(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "INP")==0)
			{ 
				res=exec_INP(counter);
				if(res!=0) return res;
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "INC")==0)
			{ 
				exec_INC(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "MAI")==0);
			else if(strcmp(p_code->codes[counter]->codeOp, "INC")==0)
			{ 
				exec_INC(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "RET")==0) counter=exec_RET(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "NOP")==0)
				counter++;
			else if(strcmp(p_code->codes[counter]->codeOp, "STA")==0)
			{ 
				exec_STA(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "LBA")==0)
			{ 
				exec_LBA(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "CAL")==0)
				counter=exec_CAL(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "LBA")==0)
			{ 
				exec_LBA(counter);
				counter++;
			}
			else return ER_EXEC;
			}
		else
		{
			if(strcmp(p_code->codes[counter]->codeOp, "MAI")==0) start=1;
			counter++;
		}
	}
	

	if(p_code->size<counter)
	{ 
		counter=0;
		nettoyerPa(pArret);
		nettoyerPile(pExecution);
		start=0;
	}

	return 0;
}

/*Execute le p_code*/
int execute()
{
	nettoyerPile(pExecution);
	nettoyerPa(pArret);
	start=0;
	counter=0;

	if(counter==-1) return ER_COUNTER;
	if(p_code->size==0) return ER_PCODE;

	int res, start=0;
	
	while(counter<p_code->size)
	{	
		if(start==1)
		{
			if(strcmp(p_code->codes[counter]->codeOp, "LOD")==0)
			{
				exec_LOD(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "LIT")==0) 
			{
				exec_LIT(counter);	
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "OPR")==0)
			{
				res=exec_OPR(counter);
				if(res!=0) return res;
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "JMP")==0)
				counter=exec_JMP(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "JPC")==0)
				counter=exec_JPC(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "SFL")==0)
			{
				exec_SFL(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "STO")==0)
			{
				res=exec_STO(counter); 
				if(res!=0) return res; 
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "OUT")==0)
			{ 
				exec_OUT(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "INP")==0)
			{ 
				res=exec_INP(counter);
				if(res!=0) return res;
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "INC")==0)
			{ 
				exec_INC(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "MAI")==0);
			else if(strcmp(p_code->codes[counter]->codeOp, "INC")==0)
			{ 
				exec_INC(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "RET")==0) counter=exec_RET(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "NOP")==0)
				counter++;
			else if(strcmp(p_code->codes[counter]->codeOp, "STA")==0)
			{ 
				exec_STA(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "LBA")==0)
			{ 
				exec_LBA(counter);
				counter++;
			}
			else if(strcmp(p_code->codes[counter]->codeOp, "CAL")==0)counter=exec_CAL(counter);
			else if(strcmp(p_code->codes[counter]->codeOp, "LBA")==0)
			{ 
				exec_LBA(counter);
				counter++;
			}	
			else return ER_EXEC;
		}
		else
		{
			if(strcmp(p_code->codes[counter]->codeOp, "MAI")==0) start=1;
			counter++;
		}
	}

	return 0;
}

void run(char commande[128])
{
	if(strcmp(commande, "exit")==0) return;
	else if(strcmp(commande, "help")==0)
	{
		printf("\nListe des commandes:\n\n");
		printf("- load : charger le p_code\n");
		printf("- pcode : consulter le pcode\n");
		printf("- reset : initialiser le compteur ordinal\n");
		printf("- exec : executer le programme\n");
		printf("- pa : definir un point d'arret\n");
		printf("- listepa : consulter les points d'arrets\n");
		printf("- resetpa : initialiser les points d'arrets\n");
		printf("- clear : nettoyer la fenetre\n");
		printf("- pile : consulter la pile d'execution\n");
		printf("- symbole : consulter la table des symboles\n");
		printf("- exit : quitter le programme\n\n");
		
	}
	else if(strcmp(commande, "exec")==0)
	{
		char error[128];
		int res;
		
		printf("\n----------------------------- EXECUTION --------------------------------\n");
		if(pArret->size>0)
		{ 
			res=execute_pa();
			printf("\n\nArret pa=%d\n", counter);	
		}
		else res=execute();
		
		
		if(res!=0)
		{
			display(res, error);
			printf("Erreur lors de l'execution du programme: %s\n", error);
		}
	
		printf("\n----------------------------- RESULTATS --------------------------------\n");
		affichagePile2(pExecution);
	}
	else if(strcmp(commande, "load")==0)
	{
		nettoyerPile(pExecution);
		nettoyerListe(tableSymbole);
		nettoyerPcode(p_code);

		loadPcode(tableSymbole, p_code, fpcode);
		printf("Done.\n");
		counter=0;
	}
	else if(strcmp(commande, "pa")==0)
	{
		int pa, res;
		printf("Ajouter un pa:");
		fflush(stdin);
		scanf("%d", &pa);

		if(0>pa || pa>=p_code->size)
		{ 
			printf("\nLe point d'arret n'est pas correct.\n");
		}
		else ajoutPa(pArret, pa);

		printf("\nDone.\n");
	}
	else if(strcmp(commande, "reset")==0)
	{
		counter=0;
		printf("Done.\n");
	}
	else if(strcmp(commande, "clear")==0) 
		system("clear");
	else if(strcmp(commande, "listepa")==0) 
		affichagePa(pArret);
	else if(strcmp(commande, "pcode")==0) 
		affichagePcode(p_code);
	else if(strcmp(commande, "resetpa")==0) 
	{
		nettoyerPa(pArret);
		nettoyerPile(pExecution);
		printf("Done.\n");
	}
	else if(strcmp(commande, "pile")==0) 
		affichagePile(pExecution);
	else if(strcmp(commande, "symbole")==0) 
		affichage(tableSymbole);
	
}

main(int argc, char *argv[])
{
	int version=2;

	if(argc<2)
	{
		printf("Vous devez specifier un fichier p_code!\n");
		exit(1);
	}

	/*Déclarations*/
	char commande[128];

	/*Ouverture du fichier p_code*/
	fpcode=fopen(argv[1], "r");
	if(fpcode==NULL)
	{
		printf("Impossible d'ouvrir le fichier pcode!\n");
		exit(2);
	}
	
	/*Construction des structures du programme*/
	pExecution=constrPile();
	tableSymbole=constrListe();
	p_code=constrPcode();
	pArret=constrPa();
	pLigne=constrPile();

	/*Info utilisateur*/
	printf("-------------------------------- Interpreteur de PCODE --------------------------------\n");
	printf("--- Version=%d. Tappez help pour plus d'information ------------------------------------\n\n", version);

	for(;;)
	{
		printf(">>");
		fflush(stdin);
		scanf("%s", commande);
		run(commande);

		if(strcmp(commande, "exit")==0) break;
	}
	
	/*run("load");run("exec");*/

	/*Nettoyage*/
	nettoyerPile(pExecution);
	nettoyerPa(pArret);
	nettoyerListe(tableSymbole);
	nettoyerPcode(p_code);
	nettoyerPile(pLigne);
}
